home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Tools 2
/
Amiga Tools 2.iso
/
tools
/
jade
/
src
/
glyphs.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-09
|
17KB
|
607 lines
/* glyphs.c -- Construction of character images
Copyright (C) 1994 John Harper <jsh@ukc.ac.uk>
This file is part of Jade.
Jade is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
Jade is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jade; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "jade.h"
#include "jade_protos.h"
#include <string.h>
#include <stdlib.h>
#ifdef NEED_MEMORY_H
# include <memory.h>
#endif
_PR long make_glyph_array(TX *, const u_char *, long, long, u_char *, long, long);
_PR long string_glyph_length(TX *, const u_char *, long);
_PR long glyph_col(TX *, long, long);
_PR long char_col(TX *, long, long);
_PR void calc_cursor_offset(VW *);
_PR void adjust_cursor_to_glyph(VW *);
_PR u_char *char_glyphs(TX *, u_char);
_PR long expand_tabs(TX *, u_char *, long, long, long, long *);
_PR void glyphtable_sweep(void);
_PR void glyphtable_prin(VALUE, VALUE);
_PR void glyphs_init(void);
_PR void glyphs_kill(void);
/* This table stores the number of glyphs which have to be printed to
make up each character. 0 is a special case -- TABSIZE spaces. */
typedef char glyph_widths_t[256];
/* This stores the glyphs which have to be printed to create each
single character, each character (except tabs) can be made of
no more than 4 glyphs. The above table is used to decide how
many to use out of the possible 4. */
typedef u_char glyph_glyphs_t[256][4];
typedef struct _GlyphTable{
u_char gt_Type;
u_char gt_Flags;
struct _GlyphTable *gt_Next;
glyph_widths_t gt_Widths;
glyph_glyphs_t gt_Glyphs;
} GlyphTable;
#define GTF_STATIC 1 /* Don't free() this table */
static GlyphTable default_glyph_table = {
V_GlyphTable,
GTF_STATIC,
NULL,
{
2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
},
{
"^@ ", "^A ", "^B ", "^C ", "^D ", "^E ", "^F ", "^G ",
"^H ", " TAB", "^J ", "^K ", "^L ", "^M ", "^N ", "^O ",
"^P ", "^Q ", "^R ", "^S ", "^T ", "^U ", "^V ", "^W ",
"^X ", "^Y ", "^Z ", "^[ ", "^\\ ", "^] ", "^^ ", "^_ ",
" ", "! ", "\" ", "# ", "$ ", "% ", "& ", "' ",
"( ", ") ", "* ", "+ ", ", ", "- ", ". ", "/ ",
"0 ", "1 ", "2 ", "3 ", "4 ", "5 ", "6 ", "7 ",
"8 ", "9 ", ": ", "; ", "< ", "= ", "> ", "? ",
"@ ", "A ", "B ", "C ", "D ", "E ", "F ", "G ",
"H ", "I ", "J ", "K ", "L ", "M ", "N ", "O ",
"P ", "Q ", "R ", "S ", "T ", "U ", "V ", "W ",
"X ", "Y ", "Z ", "[ ", "\\ ", "] ", "^ ", "_ ",
"` ", "a ", "b ", "c ", "d ", "e ", "f ", "g ",
"h ", "i ", "j ", "k ", "l ", "m ", "n ", "o ",
"p ", "q ", "r ", "s ", "t ", "u ", "v ", "w ",
"x ", "y ", "z ", "{ ", "| ", "} ", "~ ", "^? ",
"\\200", "\\201", "\\202", "\\203", "\\204", "\\205", "\\206", "\\207",
"\\210", "\\211", "\\212", "\\213", "\\214", "\\215", "\\216", "\\217",
"\\220", "\\221", "\\222", "\\223", "\\224", "\\225", "\\226", "\\227",
"\\230", "\\231", "\\232", "\\233", "\\234", "\\235", "\\236", "\\237",
"\\240", "\\241", "\\242", "\\243", "\\244", "\\245", "\\246", "\\247",
"\\250", "\\251", "\\252", "\\253", "\\254", "\\255", "\\256", "\\257",
"\\260", "\\261", "\\262", "\\263", "\\264", "\\265", "\\266", "\\267",
"\\270", "\\271", "\\272", "\\273", "\\274", "\\275", "\\276", "\\277",
"\\300", "\\301", "\\302", "\\303", "\\304", "\\305", "\\306", "\\307",
"\\310", "\\311", "\\312", "\\313", "\\314", "\\315", "\\316", "\\317",
"\\320", "\\321", "\\322", "\\323", "\\324", "\\325", "\\326", "\\327",
"\\330", "\\331", "\\332", "\\333", "\\334", "\\335", "\\336", "\\337",
"\\340", "\\341", "\\342", "\\343", "\\344", "\\345", "\\346", "\\347",
"\\350", "\\351", "\\252", "\\353", "\\354", "\\355", "\\356", "\\357",
"\\360", "\\361", "\\362", "\\363", "\\364", "\\365", "\\366", "\\367",
"\\370", "\\371", "\\372", "\\373", "\\374", "\\375", "\\376", "\\377"
}
};
static GlyphTable *gt_chain = &default_glyph_table;
/* From the array of characters SRC, build an array of glyph codes DST.
SRC contains at least SRC-LEN characters. On return, there is guaranteed
to be no more than DST-LEN glyph codes in DST, the actual number is
the return value of the function. No glyphs are copied to DST until
DST-START glyphs have gone before. SRC-ORIG is the *true glyph* position
of SRC, for calculating tab sizes. */
long
make_glyph_array(TX *tx, const u_char *src, long srcOrig, long srcLen,
register u_char *dst, long dstStart, long dstLen)
{
glyph_widths_t *width_table = &VGLYPHTAB(tx->tx_GlyphTable)->gt_Widths;
glyph_glyphs_t *glyph_table = &VGLYPHTAB(tx->tx_GlyphTable)->gt_Glyphs;
register long i = 0;
if(dstStart != 0)
{
/* Skip DSTSTART glyphs */
register long j = 0;
while((j < dstStart) && (srcLen-- > 0))
{
register int w = (*width_table)[*src++];
if(w == 0)
{
j += tx->tx_TabSize - ((j + srcOrig) % tx->tx_TabSize);
if(j > dstStart)
{
i = j - dstStart;
memset(dst, ' ', i);
dst += i;
break;
}
}
else
{
j += w;
if(j > dstStart)
{
i = j - dstStart;
memcpy(dst, &(*glyph_table)[src[-1]][w-i], i);
dst += i;
break;
}
}
}
}
while((i < dstLen) && (srcLen-- > 0))
{
register u_char c;
switch((*width_table)[c = *src++])
{
case 0:
{
/* TAB special case */
register int size = tx->tx_TabSize - ((i + srcOrig + dstStart)
% tx->tx_TabSize);
memset(dst, ' ', size);
dst += size;
i += size;
}
break;
case 1:
*dst++ = (*glyph_table)[c][0];
i++;
break;
case 2:
*dst++ = (*glyph_table)[c][0];
*dst++ = (*glyph_table)[c][1];
i += 2;
break;
case 3:
*dst++ = (*glyph_table)[c][0];
*dst++ = (*glyph_table)[c][1];
*dst++ = (*glyph_table)[c][2];
i += 3;
break;
case 4:
*dst++ = (*glyph_table)[c][0];
*dst++ = (*glyph_table)[c][1];
*dst++ = (*glyph_table)[c][2];
*dst++ = (*glyph_table)[c][3];
i += 4;
break;
}
}
return(i);
}
/* Returns the number of glyphs needed to draw the string SRC. */
long
string_glyph_length(TX *tx, const u_char *src, long srcLen)
{
glyph_widths_t *width_table = &VGLYPHTAB(tx->tx_GlyphTable)->gt_Widths;
register long w;
for(w = 0; srcLen-- > 0;)
{
register int w1 = (*width_table)[*src++];
if(w1 == 0)
w += tx->tx_TabSize - (w % tx->tx_TabSize);
else
w += w1;
}
return(w);
}
/* Return the glyph index of (COL,LINE) in TX. */
long
glyph_col(TX *tx, long col, long linenum)
{
LINE *line = tx->tx_Lines + linenum;
if(col >= line->ln_Strlen)
{
return((string_glyph_length(tx, line->ln_Line, line->ln_Strlen - 1)
+ (col - (line->ln_Strlen - 1))));
}
else
return(string_glyph_length(tx, line->ln_Line, col));
}
/* Find how many chars to glyph position col. */
long
char_col(TX *tx, long col, long linenum)
{
LINE *line = tx->tx_Lines + linenum;
u_char *src = line->ln_Line;
long srclen = line->ln_Strlen - 1;
glyph_widths_t *width_table = &VGLYPHTAB(tx->tx_GlyphTable)->gt_Widths;
register long w = 0;
while((w < col) && (srclen-- != 0))
{
register int w1 = (*width_table)[*src++];
if(w1 == 0)
w += tx->tx_TabSize - (w % tx->tx_TabSize);
else
w += w1;
}
if(srclen == -1)
return((line->ln_Strlen - 1) + (col - w));
else
return(src - line->ln_Line);
}
void
calc_cursor_offset(VW *vw)
{
TX *tx = vw->vw_Tx;
if(!((tx == vw->vw_LastCursorTx)
&& (tx->tx_Changes == vw->vw_LastCursorChanges)
&& POS_EQUAL_P(&vw->vw_CursorPos, &vw->vw_LastCursorPos)))
{
/* Have to recalculate the number of glyphs before the cursor. */
vw->vw_LastCursorOffset = glyph_col(tx, vw->vw_CursorPos.pos_Col,
vw->vw_CursorPos.pos_Line);
vw->vw_LastCursorTx = tx;
vw->vw_LastCursorChanges = tx->tx_Changes;
vw->vw_LastCursorPos = vw->vw_CursorPos;
}
}
/* Sets the vw_CursorPos.pos_Col so that the cursor's glyph pos is the same
as vw_LastCursorOffset. */
void
adjust_cursor_to_glyph(VW *vw)
{
vw->vw_CursorPos.pos_Col = char_col(vw->vw_Tx, vw->vw_LastCursorOffset,
vw->vw_CursorPos.pos_Line);
}
u_char *
char_glyphs(TX *tx, u_char ch)
{
return(&VGLYPHTAB(tx->tx_GlyphTable)->gt_Glyphs[ch][0]);
}
/* Expands any tabs in the line LINE-NUM in TX, between the glyph
positions START-GLYPH and END-GLYPH into the buffer DST. The
actual number of characters copied into DST (won't be any more
than (END-GLYPH - START-GLYPH) is returned. If WIDTH-P is non-NULL
the true width (in glyphs) of the copied portion is stored there. */
long
expand_tabs(TX *tx, u_char *dst, long start_glyph, long end_glyph,
long linenum, long *width_p)
{
LINE *line = tx->tx_Lines + linenum;
u_char *src = line->ln_Line;
u_char *orig_dst = dst;
long srclen = line->ln_Strlen - 1;
glyph_widths_t *width_table = &VGLYPHTAB(tx->tx_GlyphTable)->gt_Widths;
register long i = 0;
if(start_glyph > 0)
{
while(srclen-- != 0)
{
register int w1 = (*width_table)[*src++];
if(w1 == 0)
{
i += tx->tx_TabSize - (i % tx->tx_TabSize);
if(i > start_glyph)
{
memset(dst, ' ', i - start_glyph);
dst += i - start_glyph;
break;
}
}
else
{
i += w1;
if(i > start_glyph)
{
*dst++ = src[-1];
break;
}
}
}
}
if(srclen == -1)
return(dst - orig_dst);
while(srclen-- != 0)
{
u_char c = *src++;
register int w1 = (*width_table)[c];
if(w1 == 0)
{
w1 = tx->tx_TabSize - (i % tx->tx_TabSize);
if(w1 + i >= end_glyph)
{
memset(dst, ' ', end_glyph - i);
dst += end_glyph - i;
break;
}
memset(dst, ' ', w1);
dst += w1;
i += w1;
}
else
{
*dst++ = c;
i += w1;
if(i >= end_glyph)
break;
}
}
if(width_p)
*width_p = i - start_glyph;
return(dst - orig_dst);
}
_PR VALUE cmd_glyph_table_p(VALUE arg);
DEFUN("glyph-table-p", cmd_glyph_table_p, subr_glyph_table_p, (VALUE arg), V_Subr1, DOC_glyph_table_p) /*
::doc:glyph_table_p::
glyph-table-p ARG
Returns t if ARG is a glyph-table.
::end:: */
{
return(GLYPHTABP(arg) ? sym_t : sym_nil);
}
_PR VALUE cmd_char_to_glyph_pos(VALUE vpos, VALUE tx);
DEFUN("char-to-glyph-pos", cmd_char_to_glyph_pos, subr_char_to_glyph_pos, (VALUE vpos, VALUE tx), V_Subr2, DOC_char_to_glyph_pos) /*
::doc:char_to_glyph_pos::
char-to-glyph-pos [POS] [BUFFER]
From the character position POS, find its true *physical* position when
rendered.
::end:: */
{
POS pos;
if(!BUFFERP(tx))
tx = VAL(curr_vw->vw_Tx);
if(POSP(vpos))
pos = VPOS(vpos);
else
pos = *get_tx_cursor(VTX(tx));
pos.pos_Col = glyph_col(VTX(tx), pos.pos_Col, pos.pos_Line);
return(make_lpos(&pos));
}
_PR VALUE cmd_glyph_to_char_pos(VALUE vpos, VALUE tx);
DEFUN("glyph-to-char-pos", cmd_glyph_to_char_pos, subr_glyph_to_char_pos, (VALUE vpos, VALUE tx), V_Subr2, DOC_glyph_to_char_pos) /*
::doc:glyph_to_char_pos::
glyph-to-char-pos POS [BUFFER]
For the physical position POS, find the closest matching actual character
position.
::end:: */
{
POS pos;
if(!BUFFERP(tx))
tx = VAL(curr_vw->vw_Tx);
DECLARE1(vpos, POSP);
pos = VPOS(vpos);
pos.pos_Col = char_col(VTX(tx), pos.pos_Col, pos.pos_Line);
return(make_lpos(&pos));
}
_PR VALUE cmd_default_glyph_table(void);
DEFUN("default-glyph-table", cmd_default_glyph_table, subr_default_glyph_table, (void), V_Subr0, DOC_default_glyph_table) /*
::doc:default_glyph_table::
default-glyph-table
Returns the standard glyph-table.
::end:: */
{
return(VAL(&default_glyph_table));
}
_PR VALUE cmd_make_glyph_table(VALUE src);
DEFUN("make-glyph-table", cmd_make_glyph_table, subr_make_glyph_table, (VALUE src), V_Subr1, DOC_make_glyph_table) /*
::doc:make_glyph_table::
make-glyph-table SRC
Creates a new glyph-table. If SRC is a glyph-table it will be copied, else if
SRC is a buffer that buffer's glyph-table will be copied. If SRC is nil the
default glyph-table will be copied.
::end:: */
{
GlyphTable *newgt = mymalloc(sizeof(GlyphTable));
if(newgt)
{
GlyphTable *srcgt;
if(GLYPHTABP(src))
srcgt = VGLYPHTAB(src);
else if(BUFFERP(src))
srcgt = VGLYPHTAB(VTX(src)->tx_GlyphTable);
else
srcgt = &default_glyph_table;
memcpy(newgt, srcgt, sizeof(GlyphTable));
newgt->gt_Flags &= ~GTF_STATIC;
newgt->gt_Next = gt_chain;
gt_chain = newgt;
data_after_gc += sizeof(GlyphTable);
return(VAL(newgt));
}
return(sym_nil);
}
_PR VALUE cmd_set_glyph(VALUE gt, VALUE ch, VALUE glyph);
DEFUN("set-glyph", cmd_set_glyph, subr_set_glyph, (VALUE gt, VALUE ch, VALUE glyph), V_Subr3, DOC_set_glyph) /*
::doc:set_glyph::
set-glyph GLYPH-TABLE CHARACTER GLYPH-STRING
Make the renderer draw the string GLYPH-STRING (no more than 4 characters)
for each character CHARACTER in any buffers which use the GLYPH-TABLE.
::end:: */
{
int glyphlen;
TX *tx;
DECLARE1(gt, GLYPHTABP);
DECLARE2(ch, NUMBERP);
DECLARE3(glyph, STRINGP);
if((VNUM(ch) < 0) || (VNUM(ch) >= 256))
{
signal_arg_error(ch, 1);
return(NULL);
}
glyphlen = STRING_LEN(glyph);
if(glyphlen > 4)
{
signal_arg_error(glyph, 2);
return(NULL);
}
VGLYPHTAB(gt)->gt_Widths[VNUM(ch)] = glyphlen;
if(glyphlen == 0)
{
/* put a space in the first character */
VGLYPHTAB(gt)->gt_Glyphs[VNUM(ch)][0] = ' ';
}
else
memcpy(&VGLYPHTAB(gt)->gt_Glyphs[VNUM(ch)][0], VSTR(glyph), glyphlen);
tx = buffer_chain;
while(tx)
{
/* refresh all buffers which use this glyph table */
if(tx->tx_GlyphTable == gt)
tx->tx_Flags |= TXFF_REFRESH_ALL;
tx = tx->tx_Next;
}
return(sym_t);
}
_PR VALUE cmd_get_glyph(VALUE gt, VALUE ch);
DEFUN("get-glyph", cmd_get_glyph, subr_get_glyph, (VALUE gt, VALUE ch), V_Subr2, DOC_get_glyph) /*
::doc:get_glyph::
get-glyph GLYPH-TABLE CHARACTER
Return the string which is the rendered representation of CHARACTER in
GLYPH-TABLE.
::end:: */
{
DECLARE1(gt, GLYPHTABP);
DECLARE2(ch, NUMBERP);
if((VNUM(ch) < 0) || (VNUM(ch) >= 256))
{
signal_arg_error(ch, 1);
return(NULL);
}
return(string_dupn(&VGLYPHTAB(gt)->gt_Glyphs[VNUM(ch)][0],
VGLYPHTAB(gt)->gt_Widths[VNUM(ch)]));
}
_PR VALUE cmd_buffer_glyph_table(VALUE tx);
DEFUN("buffer-glyph-table", cmd_buffer_glyph_table, subr_buffer_glyph_table, (VALUE tx), V_Subr1, DOC_buffer_glyph_table) /*
::doc:buffer_glyph_table::
buffer-glyph-table [BUFFER]
Returns the glyph-table being used in BUFFER.
::end:: */
{
if(!BUFFERP(tx))
tx = VAL(curr_vw->vw_Tx);
return(VTX(tx)->tx_GlyphTable);
}
_PR VALUE cmd_set_buffer_glyph_table(VALUE tx, VALUE gt);
DEFUN("set-buffer-glyph-table", cmd_set_buffer_glyph_table, subr_set_buffer_glyph_table, (VALUE tx, VALUE gt), V_Subr2, DOC_set_buffer_glyph_table) /*
::doc:set_buffer_glyph_table::
set-buffer-glyph-table [BUFFER] GLYPH-TABLE
Sets the glyph-table being used in BUFFER to GLYPH-TABLE.
::end:: */
{
if(!BUFFERP(tx))
tx = VAL(curr_vw->vw_Tx);
DECLARE2(gt, GLYPHTABP);
VTX(tx)->tx_GlyphTable = gt;
VTX(tx)->tx_Flags |= TXFF_REFRESH_ALL;
return(gt);
}
void
glyphtable_sweep(void)
{
GlyphTable *gt = gt_chain;
gt_chain = NULL;
while(gt)
{
GlyphTable *nxt = gt->gt_Next;
if(!GC_MARKEDP(VAL(gt)) && !(gt->gt_Flags & GTF_STATIC))
myfree(gt);
else
{
GC_CLR(VAL(gt));
gt->gt_Next = gt_chain;
gt_chain = gt;
}
gt = nxt;
}
}
void
glyphtable_prin(VALUE strm, VALUE obj)
{
stream_puts(strm, "#<glyph-table>", -1, FALSE);
}
void
glyphs_init(void)
{
ADD_SUBR(subr_glyph_table_p);
ADD_SUBR(subr_glyph_to_char_pos);
ADD_SUBR(subr_char_to_glyph_pos);
ADD_SUBR(subr_default_glyph_table);
ADD_SUBR(subr_make_glyph_table);
ADD_SUBR(subr_set_glyph);
ADD_SUBR(subr_get_glyph);
ADD_SUBR(subr_buffer_glyph_table);
ADD_SUBR(subr_set_buffer_glyph_table);
}
void
glyphs_kill(void)
{
GlyphTable *gt = gt_chain;
while(gt)
{
GlyphTable *nxt = gt->gt_Next;
if(!(gt->gt_Flags & GTF_STATIC))
myfree(gt);
gt = nxt;
}
gt_chain = NULL;
}